package com.getpebble.android.framework.developer;

import android.content.Context;
import android.net.wifi.WifiManager;
import com.getpebble.android.PebbleApplication;
import com.getpebble.android.common.core.trace.Trace;
import com.getpebble.android.common.model.FrameworkState;
import com.getpebble.android.framework.DeviceInterfaces.IDeviceMessageSender;
import com.koushikdutta.async.ByteBufferList;
import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.callback.CompletedCallback;
import com.koushikdutta.async.callback.DataCallback;
import com.koushikdutta.async.http.WebSocket;
import com.koushikdutta.async.http.WebSocket.StringCallback;
import com.koushikdutta.async.http.libcore.RequestHeaders;
import com.koushikdutta.async.http.server.AsyncHttpServer;
import com.koushikdutta.async.http.server.AsyncHttpServer.WebSocketRequestCallback;
import com.koushikdutta.async.http.server.AsyncHttpServerRequest;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

public class DeveloperConnectionServer implements IConnection, CompletedCallback, WebSocketRequestCallback {
    public static final String TAG = DeveloperConnectionServer.class.getSimpleName();
    private final String SOCKETS_LOCK = "SOCKETS_LOCK";
    private FrameworkState mFrameworkState;
    private DeveloperConnectionManager mManager;
    private AsyncHttpServer mServer;
    private List<WebSocket> mSockets;

    public DeveloperConnectionServer(Context context, FrameworkState frameworkState, IDeviceMessageSender messageSender) throws IllegalArgumentException {
        if (context == null) {
            throw new IllegalArgumentException("'context' cannot be null!");
        } else if (frameworkState == null) {
            throw new IllegalArgumentException("'frameworkState' cannot be null!");
        } else {
            this.mFrameworkState = frameworkState;
            this.mSockets = new ArrayList();
            this.mServer = new AsyncHttpServer();
            this.mManager = new DeveloperConnectionManager(context, this, messageSender);
        }
    }

    private String defaultWifiIP() {
        try {
            return InetAddress.getByAddress(ipIntAsOctets(((WifiManager) PebbleApplication.getAppContext().getSystemService("wifi")).getConnectionInfo().getIpAddress())).getHostAddress();
        } catch (Exception e) {
            Trace.error(TAG, "Failed to get ip address", e);
            return null;
        }
    }

    private static byte[] ipIntAsOctets(int ip) {
        return new byte[]{(byte) (ip & 255), (byte) ((ip >> 8) & 255), (byte) ((ip >> 16) & 255), (byte) ((ip >> 24) & 255)};
    }

    public void start() {
        DeveloperConnectionManager.getHandler().post(new Runnable() {
            public void run() {
                DeveloperConnectionServer.this.startInternal();
            }
        });
    }

    private void startInternal() {
        this.mServer.websocket(".*", this);
        this.mServer.listen(9000);
        this.mServer.setErrorCallback(this);
        Trace.info(TAG, "DeveloperConnectionServer started: " + defaultWifiIP());
        this.mFrameworkState.setDeveloperConnectionIpAddress(defaultWifiIP());
    }

    public void stop() {
        DeveloperConnectionManager.getHandler().post(new Runnable() {
            public void run() {
                DeveloperConnectionServer.this.stopInternal();
            }
        });
    }

    private void stopInternal() {
        Trace.info(TAG, "DeveloperConnectionServer stopped: " + defaultWifiIP());
        for (WebSocket socket : this.mSockets) {
            socket.close();
        }
        this.mServer.stop();
        this.mFrameworkState.setDeveloperConnectionIpAddress(null);
        this.mManager.deInit();
    }

    public void onCompleted(Exception e) {
        Trace.error(TAG, "Got error on WebSocket", e);
    }

    public void sendMessageToAllConnections(final ByteBuffer bb) {
        DeveloperConnectionManager.getHandler().post(new Runnable() {
            public void run() {
                DeveloperConnectionServer.this.sendMessageToAllConnectionsInternal(bb);
            }
        });
    }

    private void sendMessageToAllConnectionsInternal(ByteBuffer bb) {
        for (WebSocket c : this.mSockets) {
            c.send(bb.array());
        }
    }

    public void onConnected(final WebSocket webSocket, final AsyncHttpServerRequest request) {
        DeveloperConnectionManager.getHandler().post(new Runnable() {
            public void run() {
                DeveloperConnectionServer.this.onConnectedInternal(webSocket, request);
            }
        });
    }

    private void onConnectedInternal(final WebSocket webSocket, AsyncHttpServerRequest request) {
        RequestHeaders requestHeaders = request.getHeaders();
        if (requestHeaders == null) {
            Trace.error(TAG, "onConnected: request headers were null");
            return;
        }
        final String clientName = requestHeaders.getHost();
        Trace.info(TAG, "pb-sdk connection opened: " + clientName);
        synchronized ("SOCKETS_LOCK") {
            this.mSockets.add(webSocket);
        }
        Trace.info(TAG, "Num connections: " + this.mSockets.size());
        webSocket.setClosedCallback(new CompletedCallback() {
            public void onCompleted(Exception e) {
                Trace.info(DeveloperConnectionServer.TAG, "pb-sdk connection closed: " + clientName, e);
                DeveloperConnectionServer.this.endConnection(webSocket);
            }
        });
        webSocket.setStringCallback(new StringCallback() {
            public void onStringAvailable(String message) {
                Trace.debug(DeveloperConnectionServer.TAG, "onMessage: unused message (" + clientName + "): " + message);
            }
        });
        webSocket.setDataCallback(new DataCallback() {
            public void onDataAvailable(DataEmitter dataEmitter, ByteBufferList byteBufferList) {
                for (final ByteBuffer buffer : byteBufferList.getAllArray()) {
                    DeveloperConnectionManager.getHandler().post(new Runnable() {
                        public void run() {
                            DeveloperConnectionServer.this.mManager.handleMessageFromPblSdk(buffer, DeveloperConnectionServer.this.mFrameworkState);
                        }
                    });
                }
            }
        });
        webSocket.setEndCallback(new CompletedCallback() {
            public void onCompleted(Exception e) {
                Trace.info(DeveloperConnectionServer.TAG, "pb-sdk connection ended: " + clientName, e);
                DeveloperConnectionServer.this.endConnection(webSocket);
            }
        });
        this.mFrameworkState.setDeveloperConnectionConnected(true);
    }

    private void endConnection(final WebSocket webSocket) {
        DeveloperConnectionManager.getHandler().post(new Runnable() {
            public void run() {
                DeveloperConnectionServer.this.endConnectionInternal(webSocket);
            }
        });
    }

    private void endConnectionInternal(WebSocket webSocket) {
        synchronized ("SOCKETS_LOCK") {
            this.mSockets.remove(webSocket);
            if (this.mSockets.size() == 0) {
                this.mFrameworkState.setDeveloperConnectionConnected(false);
            }
        }
    }
}
